package modlog

import (
	"os"
	"sync"

	"github.com/op/go-logging"

	"git.cloud.inspur.com/ichain/ichain-sdk-go/pkg/core/logging/api"
	"git.cloud.inspur.com/ichain/ichain-sdk-go/pkg/core/logging/metadata"
)

var (
	rwmutex      = &sync.RWMutex{}
	moduleLevels = &metadata.ModuleLevels{}
	loggerMap    = new(sync.Map)
	format       = logging.MustStringFormatter(
		`[%{level}] %{module} %{time:2006-01-02 15:04:05} [%{longfunc}]: %{message}`,
	)
)

type Provider struct {
}

func (p *Provider) GetLogger(module string) api.Logger {
	if val, ok := loggerMap.Load(module); ok {
		logger, _ := val.(*Log)
		return logger
	}

	logger := logging.MustGetLogger(module)
	modLevel := metadata.ParseString(GetLevel(module))
	level, _ := logging.LogLevel(modLevel)
	logBackend := logging.NewLogBackend(os.Stderr, "", 0)
	logBackendFormat := logging.NewBackendFormatter(logBackend, format)
	logBackendLeveled := logging.AddModuleLevel(logBackendFormat)
	logBackendLeveled.SetLevel(level, module)
	logger.SetBackend(logging.SetBackend(logBackendLeveled))
	logger.ExtraCalldepth = 2
	log := &Log{logger}

	loggerMap.Store(module, log)
	return log
}

func LoggerProvider() api.LoggerProvider {
	return &Provider{}
}

type Log struct {
	*logging.Logger
}

func SetLevel(module string, level api.Level) {
	rwmutex.Lock()
	defer rwmutex.Unlock()
	moduleLevels.SetLevel(module, level)
}

func GetLevel(module string) api.Level {
	rwmutex.RLock()
	defer rwmutex.RUnlock()
	return moduleLevels.GetLevel(module)
}

func IsEnabledFor(module string, level api.Level) bool {
	rwmutex.RLock()
	defer rwmutex.RUnlock()
	return moduleLevels.IsEnabledFor(module, level)
}

func (l *Log) Fatal(args ...interface{}) {
	l.Logger.Fatal(args)
}

func (l *Log) Fatalf(format string, args ...interface{}) {
	l.Logger.Fatalf(format, args)
}

func (l *Log) Fatalln(args ...interface{}) {
	l.Logger.Fatal(args)
}

func (l *Log) Panic(args ...interface{}) {
	l.Logger.Panic(args...)
}

func (l *Log) Panicf(format string, args ...interface{}) {
	l.Logger.Panic(args...)
}

func (l *Log) Panicln(args ...interface{}) {
	l.Logger.Panic(args...)
}

func (l *Log) Print(args ...interface{}) {
	l.Logger.Info(args...)
}

func (l *Log) Printf(format string, args ...interface{}) {
	l.Logger.Infof(format, args...)
}

func (l *Log) Println(args ...interface{}) {
	l.Logger.Info(args...)
}

func (l *Log) Debug(args ...interface{}) {
	l.Logger.Debug(args...)
}

func (l *Log) Debugf(format string, args ...interface{}) {
	l.Logger.Debugf(format, args...)
}

func (l *Log) Debugln(args ...interface{}) {
	l.Logger.Debug(args...)
}

func (l *Log) Info(args ...interface{}) {
	l.Logger.Info(args...)
}

func (l *Log) Infof(format string, args ...interface{}) {
	l.Logger.Infof(format, args...)
}

func (l *Log) Infoln(args ...interface{}) {
	l.Logger.Info(args...)
}

func (l *Log) Warn(args ...interface{}) {
	l.Logger.Warning(args...)
}

func (l *Log) Warnf(format string, args ...interface{}) {
	l.Logger.Warningf(format, args...)
}

func (l *Log) Warnln(args ...interface{}) {
	l.Logger.Warning(args...)
}

func (l *Log) Error(args ...interface{}) {
	l.Logger.Error(args...)
}

func (l *Log) Errorf(format string, args ...interface{}) {
	l.Logger.Errorf(format, args...)
}

func (l *Log) Errorln(args ...interface{}) {
	l.Logger.Error(args...)
}
